﻿// Copyright (c)  MOKEYISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.


using System;
using NSQL.Expressions;

namespace NSQL
{
    public enum JoinType : byte
    {
        Inner = 0,
        Left = 1,
        Right = 2,
        LeftOuter = 3,
        RightOuter = 4,
        FullJoin = 5,
        CrossJoin = 6
    }

    public class JoinNode : IJoinOn
    {
        public JoinType Type { get; set; }
        public ITableSource BaseTable { get; set; }
        public ITableSource JoinTable { get; set; }
        public ILogicalExpression Condition { get; set; }
        public JoinNode Previous { get; private set; }

        public static IJoinOn LeftJoin(ITableSource baseTable, ITableSource joinTable) => new JoinNode(baseTable, joinTable, JoinType.Left);
        public static IJoinOn RightJoin(ITableSource baseTable, ITableSource joinTable) => new JoinNode(baseTable, joinTable, JoinType.Right);
        public static IJoinOn InnerJoin(ITableSource baseTable, ITableSource joinTable) => new JoinNode(baseTable, joinTable, JoinType.Inner);
        public static IJoinOn LeftOuterJoin(ITableSource baseTable, ITableSource joinTable) => new JoinNode(baseTable, joinTable, JoinType.LeftOuter);
        public static IJoinOn RightOuterJoin(ITableSource baseTable, ITableSource joinTable) => new JoinNode(baseTable, joinTable, JoinType.RightOuter);

        private JoinNode(ITableSource baseTable, ITableSource joinTable, JoinType joinType)
        {
            BaseTable = baseTable;
            JoinTable = joinTable;
            Type = joinType;
        }

        public JoinNode(ITableSource baseTable, ITableSource joinTable, JoinType joinType, ILogicalExpression condition) : this(baseTable, joinTable, joinType)
        {
            Condition = condition;
        }

        /// <inheritdoc />
        ITableSource IJoinOn.On(ILogicalExpression condition)
        {
            if (BaseTable == null) throw new Exception(" Cannot join on null table.");
            Condition = condition;
            if (BaseTable.Join != null)
            {
                Previous = BaseTable.Join;
            }

            BaseTable.Join = this;
            return BaseTable;
        }
    }

    public interface IJoinOn
    {
        ITableSource On(ILogicalExpression expression);
    }
}